<template>
	<scroll-view scroll-y @scrolltolower="onScrollToBottom" :style="{ height: props.height + 'rpx' }">
		<refresh @refresh="onrefresh" @pullingdown="onpullingdown" :display="showLoading ? 'show' : 'hide'">
			<slot name="pull" :status="{ refreshStatus }">
				<view class="flex flex-row flex-row-center-center" :style="{
						height: _barHeight / 2 + 'px',
						opacity: refreshStatus == 2 || refreshStatus == 3 ? 1 : 0
					}">
					<tm-icon :font-size="24" color="primary" name="tmicon-shuaxin" spin></tm-icon>
					<zh-text color="grey" _class="pl-16" :label="loadingTexts[refreshStatus]"></zh-text>
				</view>
				<view v-if="refreshStatus != -1 && refreshStatus != 2"
					class="flex flex-row flex-row-center-center srrryration" :style="{
						opacity: `${refreshStatus == 0 ? _barHeight / nowEvt.viewHeight : 1}`,
						height: _barHeight / 2 + 'px'
					}">
					<view :class="refreshStatus == 0 ? 'srrryration srrryrationOn' : 'srrryration srrryrationOf'">
						<tm-icon :font-size="24" color="primary" name="tmicon-long-arrow-down"></tm-icon>
					</view>
					<zh-text color="grey" _class="pl-16" :label="loadingTexts[refreshStatus]"></zh-text>
				</view>
			</slot>
		</refresh>
		<slot></slot>
	</scroll-view>
</template>

<script lang="ts" setup>
	import { getCurrentInstance, nextTick, onMounted, ref, Ref, watch } from 'vue'
	import { propsdetail } from './propsdetail'
	const proxy = getCurrentInstance()?.proxy ?? null
	const emits = defineEmits(['bottom', 'change', 'refresh', 'timeout', 'update:modelValue', 'update:bottomValue'])
	const props = defineProps({
		...propsdetail
	})
	interface pullevent {
		dy : number
		pullingDistance : number
		viewHeight : number
		type : string
	}
	const showLoading = ref(false)
	const refreshing = ref(false)
	const isBootRefresh = ref(false)
	const refreshStatus = ref(-1)
	/** 开始刷新 - 刷新成功/失败 最大间隔时间setTimeout句柄 */
	let maxRefreshAnimateTimeFlag : number | null = 0
	const _barHeight = ref(uni.$tm.u.topx(props.loadBarHeight))
	const nowEvt : Ref<pullevent> = ref({
		dy: 0,
		pullingDistance: 0,
		viewHeight: 0,
		type: ''
	})

	onMounted(() => {
		if (maxRefreshAnimateTimeFlag != null) {
			clearTimeout(maxRefreshAnimateTimeFlag)
		}
	})
	watch(
		() => props.modelValue,
		() => {
			if (!props.modelValue) {
				if (maxRefreshAnimateTimeFlag != null) {
					clearTimeout(maxRefreshAnimateTimeFlag)
				}
				close()
			}
		}
	)
	watch(
		() => props.bottomValue,
		() => {
			isBootRefresh.value = props.bottomValue
		}
	)
	function onScrollToBottom() {
		if (isBootRefresh.value) return
		emits('update:bottomValue', true)
		isBootRefresh.value = true
		emits('bottom')
	}
	function onrefresh() {
		if (nowEvt.value.pullingDistance >= _barHeight.value) {
			refreshStatus.value = 2
			showLoading.value = true
			emits('refresh')
			emits('change', true)
			emits('update:modelValue', true)
			maxRefreshAnimateTimeFlag = setTimeout(() => {
				maxRefreshAnimateTimeFlag = null
				if (refreshStatus.value === 2) {
					// 超时回调
					emits('timeout')
					close() // 超时仍未被回调，则直接结束下拉
				}
			}, props.refreshTimeout as any) as any as number

			return
		}
		if (refreshStatus.value == -1 || refreshStatus.value == 0) {
			showLoading.value = true
			nextTick(() => {
				showLoading.value = false
				emits('change', false)
			})
		}
	}
	/**
		 * dy: 前后两次回调滑动距离的差值
		pullingDistance: 下拉的距离
		viewHeight: refresh 组件高度
		type: “pullingdown” 常数字符串
		 */
	function onpullingdown(evt : { dy : number; pullingDistance : number; viewHeight : number; type : string }) {
		nowEvt.value = evt

		if (evt.pullingDistance <= 1) {
			refreshStatus.value = -1
		} else if (evt.pullingDistance > 1 && evt.pullingDistance < _barHeight.value) {
			refreshStatus.value = 0
		} else if (evt.pullingDistance >= _barHeight.value) {
			refreshStatus.value = 1
		}
	}

	function close() {
		showLoading.value = false
		refreshStatus.value = 3
		emits('change', false)
		emits('update:modelValue', false)
	}
</script>

<style>
	.srrryration {
		transition-property: transform, height, opacity;
		transition-timing-function: ease;
		transition-duration: 0.25s;
	}

	.srrryrationOn {
		transform: rotate(0deg);
	}

	.srrryrationOf {
		transform: rotate(180deg);
	}
</style>